Micron Document
Gopher Proxy


gopher.conman.org:70 gopher.conman.org:70/0Boston:Src:src/main_cli.c
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/************************************************************************
*
* Copyright 2005 by Sean Conner. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Comments, questions and criticisms can be sent to: sean@conman.org
*
*************************************************************************/

#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>

#include <syslog.h>
#include <getopt.h>

#include <cgilib8/conf.h>
#include <cgilib8/rfc822.h>
#include <cgilib8/util.h>

#include "backend.h"
#include "frontend.h"
#include "blogutil.h"
#include "main.h"

typedef int (*clicmd__f)(Blog *,Request *);

/*******************************************************************/

int mailfile_readdata(Request *req)
{
FILE *output;
List headers;
assert(req != NULL);
ListInit(&headers);
RFC822HeadersRead(stdin,&headers);
req->author = safe_strdup(PairListGetValue(&headers,"AUTHOR"));
req->title = safe_strdup(PairListGetValue(&headers,"TITLE"));
req->class = safe_strdup(PairListGetValue(&headers,"CLASS"));
req->status = safe_strdup(PairListGetValue(&headers,"STATUS"));
req->date = safe_strdup(PairListGetValue(&headers,"DATE"));
req->adtag = safe_strdup(PairListGetValue(&headers,"ADTAG"));
PairListFree(&headers); /* got everything we need, dump this */
output = open_memstream(&req->origbody,&(size_t){0});
fcopy(output,stdin);
fclose(output);
req->body = strdup(req->origbody);
return 0;
}

/***************************************************************************/

static int mail_setup_data(Request *req)
{
List headers;
char *line = NULL;
assert(req != NULL);
ListInit(&headers);
getline(&line,&(size_t){0},stdin); /* skip Unix 'From ' line */
free(line);
/*----------------------------------------------------------------------
; In the past, entries have been sent that have been encoded as
; "quoted-printable". I'm not sure the exact conditions that cause it
; (recents tests with known non-7bit clean content have been passed
; through unencoded) but it is happening now that I've somewhat changed
; how I write entries with quoted material.
;
; For now, check for the existence of the Content-Transfer-Encoding header
; and if it's not '7bit', '8bit' or 'binary' (which are identity
; encodings) then stop further processing and signal an error.
;
; At some future point, we might want to decode encoded entries sent via
; email.
;-----------------------------------------------------------------------*/
RFC822HeadersRead(stdin,&headers);
char *encoding = PairListGetValue(&headers,"CONTENT-TRANSFER-ENCODING");
if (encoding)
{
down_string(encoding);
if (
(strcmp(encoding,"7bit") != 0)
&& (strcmp(encoding,"8bit") != 0)
&& (strcmp(encoding,"binary") != 0)
)
{
syslog(LOG_ERR,"Content-Transfer-Encoding of '%s' not allowed!",encoding);
PairListFree(&headers);
return EINVAL;
}
}
PairListFree(&headers);
return mailfile_readdata(req);
}

/*******************************************************************/

static int cli_error(Blog *blog,Request *request,int level,char const *msg, ... )
{
va_list args;
(void)blog;
(void)request;
assert(level >= 0);
assert(msg != NULL);
fprintf(stderr,"Error %d: ",level);
va_start(args,msg);
vfprintf(stderr,msg,args);
va_end(args);
fputc('\n',stderr);
return 1;
}

/*************************************************************************/

static int cmd_cli_error(Blog *blog,Request *req)
{
return cli_error(blog,req,HTTP_BADREQ,"Bad request");
}

/*************************************************************************/

static int cmd_cli_new(Blog *blog,Request *req)
{
int rc;
http__e status;
assert(blog != NULL);
assert(req != NULL);
if (req->f.emailin)
rc = mail_setup_data(req);
else
rc = mailfile_readdata(req);
if (rc != 0)
return cli_error(blog,req,HTTP_BADREQ,"Cannot process new entry");
status = entry_add(blog,req);
if (status < HTTP_300)
{
generate_pages(blog,req);
return 0;
}
else
return cli_error(blog,req,status,"Failed to create new entry");
}

/****************************************************************************/

static int cmd_cli_show(Blog *blog,Request *req)
{
int rc;
assert(blog != NULL);
assert(req != NULL);
if (req->f.regenerate)
rc = generate_pages(blog,req);
else if (req->f.today)
rc = generate_thisday(blog,req,stdout,blog->now);
else if (req->f.thisday)
{
if (!thisday_new(&req->tumbler,req->reqtumbler))
rc = cli_error(blog,req,HTTP_BADREQ,"bad request");
else if (req->tumbler.redirect)
rc = cli_error(blog,req,HTTP_MOVEPERM,"Redirect: %02d/%02d",req->tumbler.start.month,req->tumbler.start.day);
else
rc = generate_thisday(blog,req,stdout,req->tumbler.start);
}
else
{
if (req->reqtumbler == NULL)
{
template__t template;
template.template = blog->config.templates[0].template;
template.items = blog->config.templates[0].items;
template.pagegen = "days";
template.reverse = true;
template.fullurl = false;
rc = pagegen_days(blog,req,&template,stdout);
}
else
{
if (tumbler_new(&req->tumbler,req->reqtumbler,&blog->first,&blog->last))
{
if (req->tumbler.redirect)
{
char *tum = tumbler_canonical(&req->tumbler);
rc = cli_error(blog,req,HTTP_MOVEPERM,"Redirect: %s",tum);
free(tum);
return rc;
}
rc = tumbler_page(blog,req,&req->tumbler,cli_error);
}
else
rc = cli_error(blog,req,HTTP_NOTFOUND,"tumbler error---nothing found");
}
}
return rc;
}

/********************************************************************/

static clicmd__f get_cli_command(char const *value)
{
if (emptynull_string(value))
return cmd_cli_show;
if (strcmp(value,"new") == 0)
return cmd_cli_new;
else if (strcmp(value,"show") == 0)
return cmd_cli_show;
else if (strcmp(value,"preview") == 0)
return cmd_cli_show;
else
return cmd_cli_error;
}

/*************************************************************************/

int main_cli(int argc,char *argv[])
{
enum
{
OPT_NONE,
OPT_CONFIG,
OPT_CMD,
OPT_FILE,
OPT_EMAIL,
OPT_ENTRY,
OPT_REGENERATE,
OPT_TODAY,
OPT_THISDAY,
OPT_HELP,
};
static struct option const coptions[] =
{
{ "config" , required_argument , NULL , OPT_CONFIG } ,
{ "regenerate" , no_argument , NULL , OPT_REGENERATE } ,
{ "regen" , no_argument , NULL , OPT_REGENERATE } ,
{ "cmd" , required_argument , NULL , OPT_CMD } ,
{ "file" , required_argument , NULL , OPT_FILE } ,
{ "email" , no_argument , NULL , OPT_EMAIL } ,
{ "entry" , required_argument , NULL , OPT_ENTRY } ,
{ "today" , no_argument , NULL , OPT_TODAY } ,
{ "thisday" , required_argument , NULL , OPT_THISDAY } ,
{ "help" , no_argument , NULL , OPT_HELP } ,
{ NULL , 0 , NULL , OPT_NONE } ,
};
char *config = NULL;
clicmd__f command = cmd_cli_show;
Blog *blog;
Request request;
int rc;
request_init(&request);
while(true)
{
int option = 0;
int c = getopt_long_only(argc,argv,"",coptions,&option);
if (c == EOF)
break;
else switch(c)
{
case OPT_CONFIG:
config = optarg;
break;
case OPT_FILE:
if (freopen(optarg,"r",stdin) == NULL)
return cli_error(NULL,NULL,HTTP_ISERVERERR,"%s: %s",optarg,strerror(errno));
break;
case OPT_EMAIL:
request.f.emailin = true;
break;
case OPT_ENTRY:
request.reqtumbler = optarg;
break;
case OPT_REGENERATE:
request.f.regenerate = true;
break;
case OPT_TODAY:
request.f.today = true;
break;
case OPT_THISDAY:
request.f.thisday = true;
request.reqtumbler = optarg;
break;
case OPT_CMD:
command = get_cli_command(optarg);
break;
case OPT_HELP:
default:
fprintf(
stderr,
"usage: %s --options... \n"
"\t--config file\n"
"\t--regenerate | --regen\n"
"\t--cmd ('new' | 'show' * | 'preview')\n"
"\t--file file\n"
"\t--email\n"
"\t--entry <tumbler>\n"
"\t--today\n"
"\t--thisday <month>/<day>\n"
"\t--help\n"
"\n"
"\tVersion: mod_blog " PROG_VERSION "\n"
"\t\t%s\n"
"\t\t%s\n"
"\t* default value\n"
"",
argv[0],
cgilib_version,
LUA_RELEASE
);
return EXIT_FAILURE;
}
}
blog = BlogNew(config);
if (blog == NULL)
return cli_error(NULL,NULL,HTTP_ISERVERERR,"%s: failed to initialize",config ? config : "missing config file");
rc = (*command)(blog,&request);
BlogFree(blog);
request_free(&request);
return rc;
}

/************************************************************************/
.

you're on gopher.conman.org^70/0Boston:Src:src/main_cli.c
back link is gopher.conman.org:70/1Boston:Src:src/